/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ihm.controller;

import dao.QuestionnaireFacadeLocal;
import dao.UtilisateurFacadeLocal;
import entite.Questionnaire;
import entite.Utilisateur;
import ihm.util.Util;
import java.awt.Event;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIParameter;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.NamingException;
import javax.servlet.ServletContext;

@ManagedBean
@ViewScoped
public class MailController implements Serializable {

    // Pour que le mail fonctionne avant de décommenter cette ligne faut configuer le serveur
    // glassfish dans la partie javamail !!!
    @Resource(name = "mail/feedbackform")
    private Session serveurMailFeedBackForm;
    private String body = "body vide";
    private String sujet = "sujet vide";
    private String mailTo = "jerome.hervo@gmail.com";
    private String urlQuestionnaire = "http://www.google.fr";
    private boolean relanceMail = false;
    private String typeSujet = "defaut";
    private String nomFicHtml = "mailhtml.html";
    private Map<String, String> mapParam;
    private Map<String, Boolean> mapRendered;
    private Map<String, String> mapTypeSujet;
    File fichierHtmltemp;
    private List<String> listParametre = new ArrayList();
    private Integer idQuestionnaire = 0;
    private Integer idUtilisateur = 0;
    @ManagedProperty(value = "#{clientController}")
    private ClientController clientController;
    @ManagedProperty(value = "#{sessionController}")
    private SessionController sessionController;
    /**
     * Pour rechercher les données en base.
     */
    @EJB
    private QuestionnaireFacadeLocal questionnaireFacade;
    /**
     * Pour rechercher les données en base.
     */
    @EJB
    private UtilisateurFacadeLocal utilisateurFacade;
    /**
     * Pour ce position sur l'onglet voulu
     */
    private Integer selectedIndex = 0;

    public Integer getSelectedIndex() {
        return selectedIndex;
    }

    public void setSelectedIndex(Integer selectedIndex) {
        this.selectedIndex = selectedIndex;
    }

    /**
     * Getter Body
     * @return String : message du body
     */
    public String getBody() {
        return body;
    }

    /**
     * Setter Body
     * @param body
     */
    public void setBody(String body) {
        this.body = body;
    }

    /**
     * Getter Sujet
     * @return String : sujet du mail
     */
    public String getSujet() {
        return sujet;
    }

    /**
     * Setter sujet
     * @param sujet
     */
    public void setSujet(String sujet) {
        this.sujet = sujet;
    }

    /**
     * Getter mailTO
     * @return String: mailTo
     */
    public String getMailTo() {
        return mailTo;
    }

    /**
     * Setter mailTo
     * @param mailTo
     */
    public void setMailTo(String mailTo) {
        this.mailTo = mailTo;
    }

    /**
     * Getter NomFichHtml
     * @return String : nomFichHtml
     */
    public String getNomFicHtml() {
        return nomFicHtml;
    }

    /**
     * Setter nomFichHtml
     * @param nomFicHtml
     */
    public void setNomFicHtml(String nomFicHtml) {
        this.nomFicHtml = nomFicHtml;
    }

    /**
     * Getter RelanceMail
     * @return boolean : true si relance
     *                   false si non relance
     */
    public boolean isRelanceMail() {
        return relanceMail;
    }

    /**
     * Setter RelanceMail
     * @param relanceMail
     */
    public void setRelanceMail(boolean relanceMail) {
        this.relanceMail = relanceMail;
    }

    /**
     * Getter TypeSujet
     * @return String : TypeSujet
     */
    public String getTypeSujet() {
        return typeSujet;
    }

    /**
     * Setter TypeSujet
     * @param typeSujet
     */
    public void setTypeSujet(String typeSujet) {
        this.typeSujet = typeSujet;
    }

    /**
     * Getter UrlQuestionnaire
     * @return String : url questionnaire
     */
    public String getUrlQuestionnaire() {
        return urlQuestionnaire;
    }

    /**
     * Setter UrlQuestionnaire
     * @param urlQuestionnaire
     */
    public void setUrlQuestionnaire(String urlQuestionnaire) {
        this.urlQuestionnaire = urlQuestionnaire;
    }

    /**
     * Getter ListParametre
     * @return Liste des paramètres
     */
    public List<String> getListParametre() {
        return listParametre;
    }

    /**
     * Setter ListParametre
     * @param listParametre
     */
    public void setListParametre(List<String> listParametre) {
        this.listParametre = listParametre;
    }

    /**
     * Getter IdUtilisateur
     * @return Integer : id utilisateur
     */
    public Integer getIdUtilisateur() {
        return idUtilisateur;
    }

    /**
     * Setter IdUtilisateur
     * @param idUtilisateur
     */
    public void setIdUtilisateur(Integer idUtilisateur) {
        this.idUtilisateur = idUtilisateur;
    }

    /**
     * Getter IdQuestionnaire
     * @return Integer : Id Questionnaire
     */
    public Integer getIdQuestionnaire() {
        return idQuestionnaire;
    }

    /**
     * Setter IdQuestionnaire
     * @param idQuestionnaire
     */
    public void setIdQuestionnaire(Integer idQuestionnaire) {
        this.idQuestionnaire = idQuestionnaire;
    }

    /**
     * Setter ClientController
     * @param clientController
     */
    public void setClientController(ClientController clientController) {
        this.clientController = clientController;
    }

    /**
     * Setter SessionController
     * @param SessionController
     */
    public void setSessionController(SessionController sessionController) {
        this.sessionController = sessionController;
    }

    /**
     * Méthode d'initialisation
     */
    @PostConstruct
    public void init() {
        try {
            initMail();
        } catch (FileNotFoundException ex) {
            Util.addErrorMessage(null, "Erreur initialisation mail : " + ex.getMessage(), FacesContext.getCurrentInstance());
        } catch (IOException ex) {
            Util.addErrorMessage(null, "Erreur initialisation mail : " + ex.getMessage(), FacesContext.getCurrentInstance());
        }


        Map<String, String> parameter = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
        try {
            //si le paramètre n'est pas prèsent sa renvoi null
            afficherQuestionnaire(parameter.get("u"), parameter.get("q"), parameter.get("md5"));
        } catch (NoSuchAlgorithmException ex) {
            Util.addErrorMessage(null, "Erreur récupérer les paramètres pour afficher le questionnaire : " + ex.getMessage(), FacesContext.getCurrentInstance());
        }
    }

    /** 
     * Creates a new instance of MBMail
     */
    public MailController() {
    }

    //Integer idUtilisateur, Integer idQuestion, String mail
    /**
     *
     * @param questionnaire 
     * @param typeSujet
     * @throws NamingException
     * @throws MessagingException
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws IOException
     * @throws FileNotFoundException
     */
    public void envoieMail(Questionnaire questionnaire, String typeSujet) throws NamingException, MessagingException, NoSuchAlgorithmException, UnsupportedEncodingException, FileNotFoundException, IOException {

        changeParamGeneral(questionnaire, typeSujet);

        for (Utilisateur user : questionnaire.getUtilisateurs()) {
            changeParamUtilisateur(user);
            genererMail();
            sendMail();
        }

    }

    /**
     * Méthode de modification des paramètres généraux
     * @param questionnaire concerné
     * @param typeSujet concerné
     */
    private void changeParamGeneral(Questionnaire questionnaire, String typeSujet) {
        setTypeSujet(typeSujet);
        mapParam.put("titreQuestionnaire", questionnaire.getTitre());
        setIdQuestionnaire(questionnaire.getId());
    }

    /**
     * Méthode de modification des paramètres utilisateurs
     * @param user concerné
     */
    private void changeParamUtilisateur(Utilisateur user) {
        mapParam.put("nomUtilisateur", user.getNom());
        mapParam.put("prenomUtilisateur", user.getPrenom());
        setMailTo(user.getMail());
        setIdUtilisateur(user.getId());
    }

    /**
     * Méthode d'envoie de mail
     * @throws NamingException
     * @throws MessagingException
     */
    private void sendMail() throws NamingException, MessagingException {

        MimeMessage message = new MimeMessage(serveurMailFeedBackForm);
        message.setSubject(sujet);
        message.setRecipients(RecipientType.TO, InternetAddress.parse(mailTo, false));
        //message.setRecipients(RecipientType.CC, InternetAddress.parse("mirage36@hotmail.com", false));
        message.setContent(body, "text/html;charset=UTF-8");
        Transport.send(message);
    }

    /**
     * Méthode de génération de mail
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws FileNotFoundException
     * @throws IOException
     */
    private void genererMail() throws NoSuchAlgorithmException, UnsupportedEncodingException, FileNotFoundException, IOException {
        //Met à jour le paramètre de url
        //TODO à mettre l'url dans un fichier bundle        
        String url = "http://localhost:8080/FeedBackForm/feedBack.jsf";

        url = url + "?u=" + getIdUtilisateur();
        url = url + "&q=" + getIdQuestionnaire();
        url = url + "&md5=" + genererMD5(getIdUtilisateur(), getIdQuestionnaire());

        mapParam.put("urlQuestionnaire", url);


        //A partir du fichier temporaire remplir le body et le sujet à partir de la mapTypeSujet
        //on choisit le bon sujet et on remplace les paramètres par les valeurs
        setSujet(replaceParam(mapTypeSujet.get(getTypeSujet())));

        //Ici on remplace les paramètres du body et aussi on gére le RENDERED
        setBody(lireFichier(fichierHtmltemp));
        setBody(replaceParam(getBody()));
        setBody(activerRendered(getBody()));

    }

    /**
     * Méthode d'affichage pour les rendered
     * @param chaine
     * @return String
     */
    private String activerRendered(String chaine) {
        String s = chaine;
        for (String mapKey : mapRendered.keySet()) {
            //On supprime le code entre les balises de comportement
            if (!mapRendered.get(mapKey)) {
                boolean contientRendered = true;
                while (contientRendered) {
                    //si i contient la balise ouvrante et fermante on supprime le code au milieu puis les balises
                    if (s.contains("#RENDERED:" + mapKey + "=DEBUT") && s.contains("#RENDERED:" + mapKey + "=FIN")) {
                        s = s.substring(0, s.indexOf("#RENDERED:" + mapKey + "=DEBUT")) + s.substring(s.indexOf("#RENDERED:" + mapKey + "=FIN") + ("#RENDERED:" + mapKey + "=FIN").length());
                    } else {
                        contientRendered = false;
                    }
                }
            }
            //On supprime les balises de comportement
            s = s.replaceAll("#RENDERED:" + mapKey + "=DEBUT", "");
            s = s.replaceAll("#RENDERED:" + mapKey + "=FIN", "");
        }
        return s;
    }

    /**
     *
     * @param chaine
     * @return
     */
    private String replaceParam(String chaine) {
        String s = chaine;
        for (String mapKey : mapParam.keySet()) {
            //si le sujet contient la key
            if (s.contains("#PARAM:" + mapKey + "#")) {
                s = s.replaceAll("#PARAM:" + mapKey + "#", mapParam.get(mapKey));
            }
        }
        return s;
    }

    private String lireFichier(File fic) throws UnsupportedEncodingException, FileNotFoundException, IOException {
        String resultatFic = "";
        BufferedReader buff = new BufferedReader(new InputStreamReader(new FileInputStream(fic.getAbsolutePath()), "UTF-8"));
        try {
            String line;
            while ((line = buff.readLine()) != null) {
                resultatFic = resultatFic + line;
            }
        } finally {
            buff.close();
        }
        return resultatFic;
    }

    /**
     * méthode de génération du MD5 pour le lien vers le questionnaire à répondre
     * @param idUtilisateur
     * @param idQuestionnaire
     * @return md5
     * @throws NoSuchAlgorithmException
     */
    private String genererMD5(Integer idUtilisateur, Integer idQuestionnaire) throws NoSuchAlgorithmException {
        //à mettre dans un lieu sécuriser (bundle ?)
        //\=!ZS;;!STT0;W!jT?j?
        //Combinaison possible = 8.36682554252848e+22
        //1000000000000 soit 1000 Milliard combinaisons par secondes
        //Estimation minimale : 1326 année 201 jours 7 heures 1 mins 53 secs
        //Estimation maximale : 2653 année 37 jours 14 heures 3 mins 46 secs
        String clef = '\\' + idQuestionnaire + "=!ZS;;!STT0;W!jT?j?" + idUtilisateur;
        MessageDigest m = MessageDigest.getInstance("MD5");

        m.reset();

        m.update(clef.getBytes());
        byte[] digest = m.digest();
        BigInteger bigInt = new BigInteger(1, digest);
        String hashtext = bigInt.toString(16);
        // Now we need to zero pad it if you actually want the full 32 chars.
        while (hashtext.length() < 32) {
            hashtext = "0" + hashtext;
        }

        return hashtext;
    }

    /**
     * Méthode d'affichage du questionnaire suivant les paramètres passés en paramètres
     * @param utilisateur
     * @param questionnaire
     * @param md5
     * @throws NoSuchAlgorithmException
     */
    private void afficherQuestionnaire(String utilisateur, String questionnaire, String md5) throws NoSuchAlgorithmException {

        try {
            Integer idUtilisateur = new Integer(utilisateur);
            Integer idQuestionnaire = new Integer(questionnaire);

            //si md5 différents de null on test que le md5 fournit dans le lien est correct
            //si oui on affiche le bon questionnaire qui correspond à l'utilisateure
            if (md5 != null && md5.equals(genererMD5(new Integer(idUtilisateur), new Integer(idQuestionnaire)))) {

                clientController.setQuestionnaire(questionnaireFacade.find(idQuestionnaire));
                //affiche la page repondreQuestionnaire
                clientController.setPage("repondreQuestionnaire");
                //se position sur l'onglet Questionnaire
                setSelectedIndex(1);

                //met à jour la session de l'utilisateur authentifié
                sessionController.setUtilisateur(utilisateurFacade.find(idUtilisateur));
                System.out.println("-----mail----" + sessionController.getUtilisateur().getNom());

            }

        } catch (NumberFormatException ex) {
            //Util.addErrorMessage(null, "Erreur récupérer les paramètres pour afficher le questionnaire : " + ex.getMessage(), FacesContext.getCurrentInstance());
        }
    }

    /**
     * Méthode d'initialisation du mail
     * @throws FileNotFoundException
     * @throws IOException
     */
    private void initMail() throws FileNotFoundException, IOException {
        //récupére le chemin du fichier
        FacesContext context = FacesContext.getCurrentInstance();
        ServletContext servletContext = (ServletContext) context.getExternalContext().getContext();
        String webRoot = servletContext.getRealPath("/");

        String filePath = webRoot + "WEB-INF/includes/components/" + getNomFicHtml();

        // Création du flux bufférisé sur un FileReader, immédiatement suivi par un
        // try/finally, ce qui permet de ne fermer le flux QUE s'il le reader
        // est correctement instancié (évite les NullPointerException)
        //BufferedReader buff = new BufferedReader(new FileReader(filePath));
        //permet de conserver les accent à la lecture
        BufferedReader buff = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));

        //on écrira la partie html avec les paramètres non remplacer dans une fichier temporaire
        //celà évite de refaire tous les traitements de mise en charges des paramètres
        fichierHtmltemp = File.createTempFile("nom", ".tmp");
        fichierHtmltemp.deleteOnExit();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fichierHtmltemp), "UTF-8"));

        try {

            mapParam = new HashMap<String, String>();
            mapRendered = new HashMap<String, Boolean>();
            mapTypeSujet = new HashMap<String, String>();


            String line;
            boolean traitementEnCours = false;
            boolean htmlPretAcopie = false;
            boolean copieHtmlEnCours = false;
            // Lecture du fichier ligne par ligne. Cette boucle se termine
            // quand la méthode retourne la valeur null.
            while ((line = buff.readLine()) != null) {

                if (line.trim().equals("#TRAITEMENT:DEBUT")) {
                    traitementEnCours = true;
                }

                if (line.trim().equals("#TRAITEMENT:FIN")) {
                    traitementEnCours = false;
                    htmlPretAcopie = true;
                }

                if (htmlPretAcopie && line.trim().equals("<html>")) {
                    copieHtmlEnCours = true;
                }

                if (line.trim().equals("</html>")) {
                    if (copieHtmlEnCours) {
                        bw.write(line);
                    }
                    copieHtmlEnCours = false;
                    htmlPretAcopie = false;
                }

                if (copieHtmlEnCours) {
                    bw.write(line);
                }

                if (traitementEnCours) {

                    if (line.trim().length() > 7 && line.trim().substring(0, 7).equals("#PARAM:")) {
                        String subParam = line.trim().substring(7, line.trim().length());

                        mapParam.put(subParam, "");

                        if (subParam.equals("urlQuestionnaire")) {
                            //comme la key existe déjà sa remplace juste la valeur pas d'ajout
                            mapParam.put(subParam, getUrlQuestionnaire());
                        }

                        if (subParam.equals("nomUtilisateur")) {
                            mapParam.put(subParam, "HERVO");
                        }

                        if (subParam.equals("prenomUtilisateur")) {
                            mapParam.put(subParam, "Jérôme");
                        }

                        if (subParam.equals("titreQuestionnaire")) {
                            mapParam.put(subParam, "Titre questionnaire");
                        }

                    }

                    if (line.trim().length() > 10 && line.trim().substring(0, 10).equals("#RENDERED:")) {
                        String subComportement = line.trim().substring(10, line.trim().length());

                        mapRendered.put(subComportement, false);

                        if (subComportement.equals("relanceMail")) {
                            mapRendered.put(subComportement, isRelanceMail());
                        }
                    }

                    if (line.trim().length() > 7 && line.trim().substring(0, 7).equals("#SUJET:")) {
                        String subTypeSujet = line.trim().substring(7, line.trim().length());
                        mapTypeSujet.put(subTypeSujet.substring(0, subTypeSujet.indexOf("=")), subTypeSujet.substring(subTypeSujet.indexOf("=") + 1, subTypeSujet.length()));
                    }
                }
            }
        } finally {
            // dans tous les cas, on ferme nos flux
            buff.close();
            bw.close();
        }
    }
    //**************************************************************************
    private String numTel = "0613825828";
    private String messageSMS = "http://www.google.fr";
    private String urlQuestionnaireSMS = "http://www.google.fr";

    public String getMessageSMS() {
        return messageSMS;
    }

    public void setMessageSMS(String messageSMS) {
        setUrlQuestionnaireSMS("http://ws.red.sfr.fr/red-ws/red-b2c/resources/sms/send?responseType=xml&token=d022ef110490bb3cc2be414f28f93353&to=" + getNumTel() + "&type=PhoneNumber&msg=" + messageSMS);
        this.messageSMS = messageSMS;
    }

    public String getNumTel() {
        return numTel;
    }

    public void setNumTel(String numTel) {
        setUrlQuestionnaireSMS("http://ws.red.sfr.fr/red-ws/red-b2c/resources/sms/send?responseType=xml&token=d022ef110490bb3cc2be414f28f93353&to=" + numTel + "&type=PhoneNumber&msg=" + getMessageSMS());
        this.numTel = numTel;
    }

    public String getUrlQuestionnaireSMS() {
        return urlQuestionnaireSMS;
    }

    public void setUrlQuestionnaireSMS(String urlQuestionnaireSMS) {
        this.urlQuestionnaireSMS = urlQuestionnaireSMS;
    }

    public String submit() {
        return "http://www.google.fr";

    }
    //***************************************************************************   
    private DataModel dataModelQuestionnaireARelancer;
    private Questionnaire questionnaireRelancer;
    private List<Utilisateur> listUtilisateurRelance;
    private Utilisateur utilisateurRelancer;

    public Utilisateur getUtilisateurRelancer() {
        return utilisateurRelancer;
    }

    public void setUtilisateurRelancer(Utilisateur utilisateurRelancer) {
        this.utilisateurRelancer = utilisateurRelancer;
    }

    public List<Utilisateur> getListUtilisateurRelance() {
        return listUtilisateurRelance;
    }

    public void setListUtilisateurRelance(List<Utilisateur> listUtilisateurRelance) {
        this.listUtilisateurRelance = listUtilisateurRelance;
    }

    public Questionnaire getQuestionnaireRelancer() {
        return questionnaireRelancer;
    }

    public void setQuestionnaireRelancer(Questionnaire questionnaireRelancer) {
        this.questionnaireRelancer = questionnaireRelancer;
    }

    public DataModel getDataModelQuestionnaireARelancer() {
        return dataModelQuestionnaireARelancer;
    }

    public void setDataModelQuestionnaireARelancer(DataModel dataModelQuestionnaireARelancer) {
        this.dataModelQuestionnaireARelancer = dataModelQuestionnaireARelancer;
    }

    public void afficherRelanceQuestionnaire() {
        dataModelQuestionnaireARelancer = new ListDataModel(questionnaireFacade.questionnaireRelancable());
    }

    public void afficherRelanceUtilisateur(){
        setListUtilisateurRelance((List<Utilisateur>) questionnaireRelancer.getUtilisateurs());
    }

    public void relancerQuestionnaireSMS(){
        setNumTel(utilisateurRelancer.getMail());
        setMessageSMS("Ceci+est+une+relance+"+utilisateurRelancer.getNom()+"+!+pour+le+questionnaire+"+questionnaireRelancer.getTitre());
    }
}
